package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.enums.content.TeachPlanEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.TeachplanConvert;
import com.xuecheng.content.entity.Teachplan;
import com.xuecheng.content.entity.TeachplanMedia;
import com.xuecheng.content.entity.ext.TeachplanNode;
import com.xuecheng.content.mapper.TeachplanMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.TeachplanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 课程计划 服务实现类
 * </p>
 */
@Service
public class TeachplanServiceImpl extends ServiceImpl<TeachplanMapper, Teachplan> implements TeachplanService {
    @Autowired
    private CourseBaseService courseBaseService;


    @Autowired
    private TeachplanService teachplanService;
    /*
    * 业务分析：
    *   1.判断关键数据
    *       courseId companyId
    *   2.判断业务数据
    *       课程基础信息
    *           判断是否存在
    *           判断是否是同一家教学机构
    *           判断是否删除
    *   3.根据Courseid查询课程计划数据
    *   4.通过java的递归生成课程计划树形结构
    *   5.将数据转为dto并返回
    * */

    @Override
    public TeachplanDTO queryTreenodesByCourseId(Long courseBaseId,Long companyId) {

//        业务分析：
//        1.判断关键数据
//        courseId companyId
//        2.判断业务数据
//                课程基础信息
//        判断是否存在
//                判断是否是同一家教学机构
//        判断是否删除
        courseBaseService.getCourseById(courseBaseId,companyId);
//        3.根据Courseid查询课程计划数据

        TeachplanMapper baseMapper = this.getBaseMapper();

        List<TeachplanNode> nodes = baseMapper.selectByCourseId(courseBaseId);
        TeachplanDTO dto=null;
        if(CollectionUtils.isEmpty(nodes)){
            dto=new TeachplanDTO();
        }else{
            //用完直接移除根节点
            TeachplanNode node = nodes.get(0);
            TeachplanNode root = nodes.remove(0);

            if(CollectionUtils.isEmpty(nodes)){
                dto=new TeachplanDTO();
            }else{
                // 直接生成一个树形结构存放课程计划
                //        4.通过java的递归生成课程计划树形结构
                generatetreeNodes(root,nodes);
                dto=TeachplanConvert.INSTANCE.node2dto(root);
            }
        }

//        5.将数据转为dto并返回
        return dto;
    }



    /**
     *  递归方法：
     *
     * @param currentNode  当前集合
     * @param nodes  子集集合数据  （二级，三级）
     */

    private void generatetreeNodes(TeachplanNode currentNode, List<TeachplanNode> nodes) {
        // 判断父级的自己的数据是否存在，若不存在创建一个。主要是第二级用
        if(ObjectUtils.isEmpty(currentNode.getChildrenNode())){
            currentNode.setChildrenNode(new ArrayList<TeachplanNode>());
        }
        //如果有元素的对象的父亲id=当前id  则证明这个节点是当前节点的子节点
        for (TeachplanNode node : nodes) {
            if(node.getParentid().equals(currentNode.getId())){

                //将node 存到当前对象的ChildrenNode中
                currentNode.getChildrenNode().add(node);

                //跳出条件，就是当级数是3 的时候  没有儿子
                if(!(node.getGrade().equals(TeachPlanEnum.THIRD_LEVEL))){
                    generatetreeNodes(node,nodes);
                }
            }

        }


    }



    @Override
    @Transactional
    public TeachplanDTO createOrModifyTeachplan(TeachplanDTO dto, Long companyId) {
        /**
         *  0. 是否开启事务
         *  1. 判断请求参数
         *  2. 判断业务参数
         *  3. 决定进行操作
         *  4. 进行操作
         *  5. 返回结果
         *
         */
//        0. 是否开启事务  是
//        1. 判断请求参数
        Long teachPlanId = dto.getTeachPlanId();
        TeachplanDTO resultDTO=null;
//        2. 判断业务参数
//        3. 决定进行操作
        if(ObjectUtils.isEmpty(teachPlanId)){
            // 若是空 就增
            resultDTO= createCourseBase(dto,companyId);
        }
        else {
            resultDTO= updateCourseBase(dto,companyId);
        }
//        4. 进行操作
//        5. 返回结果
        return resultDTO;
    }

    @Override
    @Transactional
    public void removeTeachplan(String teachPlanId, Long companyId) {
        /**
         *  0. 是否开启事务
         *  1. 判断关键数据
         *  2. 判断业务数据
         *  3. 业务
         */
        //1.判断关键数据的合法性
        if (ObjectUtils.isEmpty(teachPlanId)||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        Teachplan teachplan = this.getById(teachPlanId);

        if (ObjectUtils.isEmpty(teachplan)) ExceptionCast.cast(ContentErrorCode.E_120402);

        // 判断是否是一级课程计划，如果是应该抛出异常
        if (ObjectUtils.nullSafeEquals(TeachPlanEnum.FIRST_PARENTID_FLAG,teachplan.getParentid())) {
            ExceptionCast.cast(ContentErrorCode.E_120417);
        }
        // 课程基础信息  判断课程在不在，
        //     课程基础信息
        //         判断是否存在
        //         判断是否同一家机构
        //         判断是否删除
        //         判断课程基础信息审核状态：未提交和审核未通过
        CourseBaseDTO coursebase = getCourseAndVerify(companyId, teachplan.getCourseId());
        // 判断是否是二级
        if(teachplan.getGrade()==TeachPlanEnum.SECEND_LEVEL){
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid,teachplan.getId());
            int count = count(queryWrapper);
            if(count>0){
                ExceptionCast.cast(ContentErrorCode.E_120409);
            }


        }else {    // 判断是否是3级
            String teachmode = coursebase.getTeachmode();
            if (CourseModeEnum.COURSE_MODE_RECORD_STATUS.getCode().equals(teachmode)) {
                LambdaQueryWrapper<TeachplanMedia>
                        mediaLambdaQueryWrapper = new LambdaQueryWrapper<>();

                mediaLambdaQueryWrapper.eq(TeachplanMedia::getTeachplanId,teachPlanId);

//                int mediaCount = teachplanMediaService.count(mediaLambdaQueryWrapper);
//
//                if (mediaCount > 0) ExceptionCast.cast(ContentErrorCode.E_120413);
            }

            removeById(teachPlanId);
        }

    }


    private CourseBaseDTO getCourseAndVerify(Long companyId, Long courseId) {
        //     课程基础信息
        //         判断是否存在
        //         判断是否同一家机构
        //         判断是否删除
        //         判断课程基础信息审核状态：未提交和审核未通过
        CourseBaseDTO courseBase = courseBaseService.getCourseById(courseId, companyId);

        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }
        return courseBase;
    }

    private TeachplanDTO updateCourseBase(TeachplanDTO dto, Long companyId) {
        /**
         * 1. 判断关键数据
         *      课程计划id
         *      父级id值
         *      课程计划名单
         *      课程id值
         *2. 判断业务数据
         *      课程基础信息
         *          判断是否存在
         *          判断是否是同一个教学机构
         *          判断是否删除
         *          判断审核状态： 只有未提交和审核未通过 才能修改课程计划
         */
//        1. 判断关键数据
//        pname,grade courseid
        if(ObjectUtils.isEmpty(dto.getPname())|| ObjectUtils.isEmpty(dto.getGrade())|| ObjectUtils.isEmpty(dto.getCourseId())){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
//       2. 判断业务数据
//                课程基础信息
//        判断是否存在
//                判断是否是同一个教学机构
//        判断是否删除     这三个由CourseById 判短
        CourseBaseDTO courseBase = courseBaseService.getCourseById(dto.getCourseId(), companyId);
//       判断审核状态： 只有未提交和审核未通过 才能修改课程计划   需要单独判断
        String auditStatus = courseBase.getAuditStatus();
        if(auditStatus.equals(CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode())||
                auditStatus.equals(CourseAuditEnum.AUDIT_PASTED_STATUS.getCode())||
                auditStatus.equals(CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode())){
            throw new RuntimeException("课程状态异常");
        }
      //3。 判断课程计划是否存在
        Teachplan teachplan = this.getById(dto.getTeachPlanId());

        if(ObjectUtils.isEmpty(teachplan)){
            // 为空直接异常
            ExceptionCast.cast(ContentErrorCode.E_120402);
        }
        Long parentid = teachplan.getParentid();

        if(parentid.equals(TeachPlanEnum.FIRST_PARENTID_FLAG)){
            // 如果是第一级   直接异常
//            不让修改第一ji
            throw new RuntimeException("第一级不让修改");
        }
//  不是一级，可以进行以下操作
//     前端只能修改某些字段
        LambdaUpdateWrapper<Teachplan> updateWrapper = new LambdaUpdateWrapper<>();

        updateWrapper.set(Teachplan::getPname,dto.getPname());
        updateWrapper.set(Teachplan::getIsPreview,dto.getIsPreview());
        updateWrapper.set(Teachplan::getStartTime,dto.getStartTime());
        updateWrapper.set(Teachplan::getEndTime,dto.getEndTime());
        updateWrapper.set(Teachplan::getChangeDate,dto.getChangeDate());

        updateWrapper.eq(Teachplan::getId,dto.getTeachPlanId());

        boolean update = this.update(updateWrapper);
        if(!update){
            ExceptionCast.cast(ContentErrorCode.E_120407);
        }
        
        // 返回 修改后的数据
        Teachplan po = this.getById(dto.getTeachPlanId());
        TeachplanDTO resultDTO = TeachplanConvert.INSTANCE.entity2dto(po);
        return resultDTO;
    }

    private TeachplanDTO createCourseBase(TeachplanDTO dto, Long companyId) {
        /**
         *   1. 判断关键数据
         *   pname,grade courseid
         *
         *  2. 判断业务数据
         *      课程基础信息
         *          判断是否存在
         *          判断是否是同一个教学机构
         *          判断是否删除     这三个由CourseById 判短
         *          判断审核状态： 只有未提交和审核未通过 才能修改课程计划   需要单独判断
         *
         *  3. 获得父级数据
         *      添加课程的parentid=父级的id
         *      添加的grade =父级的grade+1
         *      父级的orderBy属性 是该章节的子节点个数+1
         *
         *  4. 保存课程计划到数据库
         */
//        1. 判断关键数据
//        pname,grade courseid
        if(ObjectUtils.isEmpty(dto.getPname())|| ObjectUtils.isEmpty(dto.getGrade())|| ObjectUtils.isEmpty(dto.getCourseId())){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
//        判断业务数据
//                课程基础信息
//        判断是否存在
//                判断是否是同一个教学机构
//        判断是否删除     这三个由CourseById 判短
        CourseBaseDTO courseBase = courseBaseService.getCourseById(dto.getCourseId(), companyId);
//       判断审核状态： 只有未提交和审核未通过 才能新增课程计划   需要单独判断
        String auditStatus = courseBase.getAuditStatus();
        if(auditStatus.equals(CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode())||
           auditStatus.equals(CourseAuditEnum.AUDIT_PASTED_STATUS.getCode())||
           auditStatus.equals(CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode())){
            throw new RuntimeException("课程状态异常");
        }


        //3. 获得父级数据
        //    添加课程的parentid=父级的id
        //    添加的grade =父级的grade+1
        //    父级的orderBy属性 是该章节的子节点个数+1
       Teachplan parentNode= getParentNode(courseBase,dto);
        dto.setGrade((parentNode.getGrade()+1)+"");
        dto.setParentid(parentNode.getId());

        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(Teachplan::getParentid,parentNode.getId());

        int count = this.count(queryWrapper);

        dto.setOrderby(count+1);

        Teachplan teachplan = TeachplanConvert.INSTANCE.dto2entity(dto);

        boolean flag = this.save(teachplan);

        if(!flag){
            throw new RuntimeException("保存失败");
        }

       return dto;
    }

//    private Teachplan getParentNode(CourseBaseDTO courseBase, TeachplanDTO dto) {
//
//        // 没有父级    二级
//       if(ObjectUtils.isEmpty(dto.getParentid())){
////           父级不存在 创建
//           LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
//
//           queryWrapper.eq(Teachplan::getCourseId,dto.getCourseId());
//           queryWrapper.eq(Teachplan::getParentid,TeachPlanEnum.FIRST_PARENTID_FLAG);
//           queryWrapper.eq(Teachplan::getGrade,TeachPlanEnum.FIRST_LEVEL);
//
//           Teachplan root = this.getOne(queryWrapper);
//
//           if(ObjectUtils.isEmpty(root)){   // 不存在  新建一个
//               root=new Teachplan();
//               root.setPname(courseBase.getName());
//               root.setParentid(new Long(TeachPlanEnum.FIRST_PARENTID_FLAG));
//               root.setGrade(TeachPlanEnum.FIRST_LEVEL);
//               root.setOrderby(TeachPlanEnum.FIRST_LEVEL);
//               root.setCourseId(courseBase.getCourseBaseId());
//
//               boolean save = this.save(root);
//               if(!save){
//                   ExceptionCast.cast(ContentErrorCode.E_120407);
//               }
//
//           }  // 存在直接返回
//           return root;
//
//        // 有父级     三级
//       }else{
//           //           父级不存在 异常
//           LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
//           queryWrapper.eq(Teachplan::getParentid,dto.getParentid());
//
//           Teachplan root = this.getOne(queryWrapper);
//
//           //不存在  报异常
//           if(ObjectUtils.isEmpty(root)){
//               ExceptionCast.cast(ContentErrorCode.E_120408);
//           }
//
////           存在 返回就行
//           return root;
//           }
////             父级存在  添加
//
//       }
//
/*
 * 业务分析：
 *  1.判断添加的课程计划是几级数据
 *     前端只能操作：2级和3级
 *     区分：三级课程计划添加时需要携带parentid
 *  2.获得父级数据
 *     获得二级
 *        如果获得父级数据不存在：自动在后端创建
 *        如果获得父级数据存在：直接返回
 *     获得三级
 *        如果获得父级数据不存在：直接抛出异常
 *        如果获得父级数据存在：直接返回
 * */
private Teachplan getParentNode(CourseBaseDTO courseBase, TeachplanDTO dto) {


    //1.判断添加的课程计划是几级数据
    //    前端只能操作：2级和3级
    //    区分：三级课程计划添加时需要携带parentid
    // 2.获得父级数据
    if (ObjectUtils.isEmpty(dto.getParentid())) {
        //    获得二级
        //       如果获得父级数据不存在：自动在后端创建
        //       如果获得父级数据存在：直接返回
        //     select * from teachplan where courseid = ? and parentid = 0  and grade = 1
        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teachplan::getParentid, TeachPlanEnum.FIRST_PARENTID_FLAG);
        queryWrapper.eq(Teachplan::getCourseId, courseBase.getCourseBaseId());

        Teachplan rootNode = this.getOne(queryWrapper);

        if (ObjectUtils.isEmpty(rootNode)) {

            rootNode = new Teachplan();
            rootNode.setPname(courseBase.getName());
            rootNode.setParentid(new Long(TeachPlanEnum.FIRST_PARENTID_FLAG));
            rootNode.setGrade(TeachPlanEnum.FIRST_LEVEL);
            // rootNode.setDescription(courseBase.getDescription());
            rootNode.setOrderby(TeachPlanEnum.FIRST_LEVEL);
            rootNode.setCourseId(courseBase.getCourseBaseId());

            boolean result = this.save(rootNode);
            if (!result) {
                ExceptionCast.cast(ContentErrorCode.E_120407);
            }
        }
        return rootNode;
    } else {
        //    获得三级
        //       如果获得父级数据不存在：直接抛出异常
        //       如果获得父级数据存在：直接返回
        //     select * from teachplan parentid = ?
        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teachplan::getId, dto.getParentid());

        Teachplan parentNode = this.getOne(queryWrapper);

        if (ObjectUtils.isEmpty(parentNode)) {
            ExceptionCast.cast(ContentErrorCode.E_120408);
        }

        return parentNode;
    }
}


}